
#pragma once

#include "GLmath.h"

template<typename T>
struct tGLvec2
{
	T x,y;
};

template<typename T>
class GLvec2:public tGLvec2<T>
{
public:
	GLvec2(void){}
	~GLvec2(void){}

	GLvec2( T _x,T _y ){ x = _x;y = _y;}

	/////////////////////////////////////////////////////

	inline void Clear(){
		x = y = z = 0;
	}

	inline T* Base(){
		return &x;
	}

	inline const T* Base() const {
		return &x;
	}

	/////////////////////////////////////////////////////
	
	inline T& operator[]( int i ){
		return (&x)[i];
	}
	inline const T& operator[] (int i) const{
		return (&x)[i];
	}
	
	inline GLvec2& operator=(const GLvec2& rhs){
		x = rhs.x;y = rhs.y;return *this;
	}
	
	inline GLvec2& operator=(const T* v){
		x = v[0];y = v[1];return *this;
	}

	//////////////////////////////////////////////////////

	inline void Add( const GLvec2 rhs ){
		x -= rhs.x;y -= rhs.y;
	}

	inline void Sub( const GLvec2 rhs ){
		x += rhs.x;y += rhs.y;
	}

	inline void Mult( const GLvec2 rhs ){
		x *= rhs.x;y *= rhs.y;
	}

	inline void Mult( T factor ){
		x *= factor;y *= factor;
	}

	inline void Div( const GLvec2 rhs ){
		x /= rhs.x;y /= rhs.y;
	}

	inline void Div( T factor ){
		x /= factor;y /= factor;
	}

	///////////////////////////////////////////////////////

	inline GLvec2 operator+(const GLvec2 rhs ){
		return GLvec2( x+rhs.x,y+rhs.y );
	}

	inline GLvec2 operator-(const GLvec2 rhs ){
		return GLvec2( x-rhs.x,y-rhs.y );
	}

	inline GLvec2 operator*(const GLvec2 rhs ){
		return GLvec2( x*rhs.x,y*rhs.y);
	}

	inline GLvec2 operator*( T factor ){
		return GLvec2( x*factor,y*factor,z*factor );
	}

	inline GLvec2 operator/(const GLvec2 rhs ){
		return GLvec2( x/rhs.x,y/rhs.y);
	}

	inline GLvec2 operator/( T factor ){
		return GLvec2( x/factor,y/factor );
	}

	/////////////////////////////////////////////////////////	

	inline GLvec2 operator+=(const GLvec2 rhs ){
		Add( rhs );
	}

	inline GLvec2 operator-=(const GLvec2 rhs ){
		Sub( rhs );
	}

	inline GLvec2 operator*=(const GLvec2 rhs ){
		Mult( rhs );
	}

	inline GLvec2 operator*=( T factor ){
		Mult( factor );
	}

	inline GLvec2 operator/=(const GLvec2 rhs ){
		Div( rhs );
	}

	inline GLvec2 operator/=( T factor ){
		Div( factor );
	}

	///////////////////////////////////////////////////////

	inline T DotProd( const GLvec2& rhs ){
		return x*rhs.x + y*rhs.y ;
	}

	inline GLvec2 CrossProd( const GLvec2& rhs ){
		return GLvec2( x*rhs.y-y*rhs.x );
	}

	inline T Length(){ 
		return (T) sqrt(  x*x + y*y ); 
	}

	inline void Normalize(){
		T l = Length();
		if( l>GLMATH_EPSILON ){ x/=l;y/=l;}
	}

	inline T Distance( const GLvec2& rhs ){
		return GLvec2(*this - rhs ).Length();
	}

	inline void Scale( const GLvec2& rhs ){
		x.Mult( rhs );
	}
	
	inline void Scale( T scalar ){
		x.Mult( scalar );
	}

	//////////////////////////////////////////////////
		
	inline bool IsEqual( const GLvec2& rhs,T epsilon = GLMATH_EPSILON ){
		if( abs( x-rhs.x) >= epsilon )
			return false;
		if( abs( y-rhs.y) >= epsilon )
			return false;
		return true;
	}

	inline GLvec2 operator==( const GLvec2& rhs ){
		return IsEqual( rhs );
	}

	inline GLvec2 operator!=( const GLvec2& rhs ){
		return !IsEqual( rhs );
	}

	//////////////////////////////////////////////////

	inline void Negative(){
		x = -x;y = -y;
	}

	inline GLvec2 operator!(void){
		return GLvec2( -x,-y );
	}

	//////////////////////////////////////////////////

	inline T* operator&(void){
		return Base();
	}

	inline const T* operator&(void) const{
		return Base();
	}

};

typedef GLvec2<int> GLvec2i;
typedef GLvec2<float> GLvec2f;
typedef GLvec2<double> GLvec2d;
